package de.pyranja.storage.spring;

import static com.google.common.base.Preconditions.checkArgument;

import java.io.File;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import org.apache.jdbm.DB;
import org.apache.jdbm.DBMaker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.env.Environment;

import de.pyranja.storage.core.Archive;
import de.pyranja.storage.core.Staging;
import de.pyranja.storage.core.Storage;
import de.pyranja.storage.support.BlobToFile;
import de.pyranja.storage.support.FlatResolver;

/**
 * Declares core components of BinaryStorage module in spring context.
 * @author Chris Borckholder
 */
@Configuration
@PropertySource("classpath:config/binary-storage.properties")
public class CoreConfig {

	public static final String STORAGE_DIRECTORY = "storage";
	public static final String STAGING_DIRECTORY = "staging";
	public static final String ARCHIVE_DB_FILE = "archive";
	public static final String DEF_HASH_ALGORITHM = "MD5";
	
	@Autowired Environment env;
	
	/* required context */
	
	@Bean
	File storageRoot() {
		File root = new File(env.getRequiredProperty("de.pyranja.storage.root"));
		checkArgument(root.isDirectory(), "invalid root directory for binary storage: %s", root);
		return root;
	}
		
	/* core components */
	
	@Bean
	public Staging staging() throws NoSuchAlgorithmException, IOException {
		String hash = env.getProperty("de.pyranja.storage.hash", DEF_HASH_ALGORITHM);
		MessageDigest digester = MessageDigest.getInstance(hash);
		return new Staging(make(STAGING_DIRECTORY), digester);
	}
	
	@Bean(destroyMethod = "shutdown")
	public Archive archive() {
		String dbFile = new File(storageRoot(),ARCHIVE_DB_FILE).getAbsolutePath();
		DB database = DBMaker.openFile(dbFile).disableTransactions().make();
		return new Archive(database);
	}
	
	@Bean(destroyMethod = "shutdown")
	public Storage storage() throws NoSuchAlgorithmException, IOException { 
		BlobToFile resolver = new FlatResolver(make(STORAGE_DIRECTORY));
		return new Storage(resolver, staging());
	}
	
	/* helper */ 
	
	private File make(String directory) {
		File result = new File(storageRoot(), directory);
		result.mkdir();
		return result;
	}
}
